/**
YASTACS random number generator with state.

Authors: Kalman Kiss, kiskami@freemail.hu

Bugs:

Date: 

License: GNU General Public License

YASTACS game
Copyright (C) 2012 Kalman Kiss, kiskami@freemail.hu

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Contact author at: kiskami@freemail.hu or
Hungary, 8900 Zalaegerszeg
Kakukkfu u 4.
*/
module ugen.RandomSource;

import std.random;

import util.json;

/// std.random wrapper
class RandomSource {

	this(in string seed_, in uint startoffset_=0, in uint mainrnd_max_=1000) {
		startoffset = startoffset_;
		mainrnd_max = mainrnd_max_;
		seed = seed_;
		mainrnd.seed(hash(seed));
		if(startoffset_>0) {
			for(uint i = 0;	i < startoffset_; ++i) getNextMainRnd();
			rndcount = startoffset;
		}
	}

	string toJson(bool pretty=false) {
		JSONObject root = new JSONObject();

		root["seed"] = new JSONString(seed);
		root["startoffset"] = new JSONNumber(rndcount);
		root["rndmax"] = new JSONNumber(rndcount);

		return pretty?root.toPrettyString:root.toString;
	}

	static RandomSource createFromJson(string json) {
		auto jo = readJSON(json);

		return new RandomSource(jo["seed"].toJSONString().get()
								, to!uint(jo["startoffset"].toJSONNumber().get())
								, to!uint(jo["rndmax"].toJSONNumber().get()));
	}

	bool checkProbability(float prob) {
		return getNextMainRnd()<=mainrnd_max*prob;
	}

	uint getNextMainRnd() {
		return getNextMainRnd(mainrnd_max);
	}

	uint getNextMainRnd(uint max) {
		return getNextMainRnd(0, max);
	}

	uint getNextMainRnd(uint min, uint max) {
		++rndcount;
		return uniform(min, max, mainrnd);
	}

	uint dice(immutable float[] proportions) {
		++rndcount;
		return std.random.dice(mainrnd, proportions);
	}

private:
	Random mainrnd;
	uint startoffset
		, rndcount
		, mainrnd_max;
	string seed;

	uint hash(in string seedstr) {
		// TODO maybe implement something better, like http://burtleburtle.net/bob/c/lookup3.c

		ulong ul=0;
		foreach(immutable char c ; seedstr) {
			ul = 33 * ul + c;
			//			ul += (ul >> 5);
		}
		//		debug writeln("seedstr is: ", seedstr, ", seed is: ", ul % uint.max);
		return ul % uint.max;
	}

};
